package com.hjy.backend.dataManager.pageCache;


import com.hjy.backend.dataManager.page.Page;
import com.hjy.common.error.Error;
import com.hjy.backend.utils.Panic;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

/**
 * page缓存对象, 用于管理 page页,
 * <p>
 * 在 Page 创建时会将内存数据存储到磁盘,
 * 在该页面没有人用的时候会将数据存储到磁盘
 */
public interface PageCache {

    public static final int PAGE_SIZE = 1 << 13; // 页面大小, 默认是 8K


    /**
     * 创建一个新的页面
     *
     * @param initData
     * @return
     */
    int newPage(byte[] initData);

    /**
     * 从缓存中获取页面
     *
     * @param pageId
     * @return
     * @throws Exception
     */
    Page getPage(int pageId) throws Exception;

    void close();

    /**
     * 从缓存中释放页面
     *
     * @param page
     */
    void release(Page page);

    /**
     * 截断数据文件
     *
     * @param maxPageId
     */
    void truncateByPageId(int maxPageId);

    /**
     * 获取当前最后一个页面的序号
     *
     * @return
     */
    int getPageNumber();

    /**
     * 将当前页面写进磁盘
     *
     * @param pg
     */
    void flushPage(Page pg);

    /**
     * 创造一个pageCache
     *
     * @param path
     * @param memory
     * @return
     */
    public static PageCacheImpl create(String path, long memory) {
        File f = new File(path + PageCacheImpl.DB_SUFFIX);
        try {
            if (!f.createNewFile()) {
                Panic.panic(Error.FileCannotRWException);
            }
        } catch (Exception e) {
            Panic.panic(e);
        }
        if (!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(f, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }
        return new PageCacheImpl(raf, fc, (int) memory / PAGE_SIZE);
    }

    /**
     * 根据文件位置打开一个pageCache
     *
     * @param path
     * @param memory
     * @return
     */
    public static PageCacheImpl open(String path, long memory) {
        File f = new File(path + PageCacheImpl.DB_SUFFIX);
        if (!f.exists()) {
            Panic.panic(Error.FileNotExistsException);
        }
        if (!f.canRead() || !f.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }

        FileChannel fc = null;
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(f, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }
        return new PageCacheImpl(raf, fc, (int) memory / PAGE_SIZE);
    }
}
